﻿using UnityEngine;
using UnityEngine.EventSystems;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace Jinndev.GameKit {

    /// <summary>
    /// 物品视图，基于Inventory和Item实现
    /// </summary>
    public class ItemView : BaseUIBehaviour {

        /// <summary>
        /// 默认图标预设路径，可更改，优先级低于customItemPrefab
        /// </summary>
        public static string DefaultItemPrefab = ItemIcon.PATH;

        [Header("视图配置")]
        [Tooltip("视图实现类型，使用GridView实现、使用普通容器实现")]
        public ViewType viewType = ViewType.Container;
        public GridView gridView;
        public RectTransform container;

        [Header("自定义图标预设")]
        [Tooltip("继承自IItemUI的自定义图标预设，留空则使用默认预设DefaultItemPrefab")]
        public IItemUI customItemPrefab;

        [Header("图标配置")]
        [Tooltip("是否显示背景")]
        public bool showBg = true;
        [Tooltip("是否显示序号")]
        public bool showIndex = false;
        [Tooltip("起始序号")]
        public int indexOffset = 1;
        [Tooltip("是否显示数量")]
        public bool showNum = true;
        [Tooltip("是否显示最大数量")]
        public bool showMaxNum = false;
        [Tooltip("是否显示选中框")]
        public bool showSelected = false;
        [Tooltip("重复选中相同物品是否可以取消选中")]
        public bool toggleSelected = false;
        [Tooltip("数量的显示格式(可选)")]
        public string numFormat = "";

        [Header("库存配置")]
        [Tooltip("数量为0时是否设置为空物品")]
        public bool setEmptyOnZero = true;
        [Tooltip("是否启用拾取拖放操作")]
        public bool enablePickAndDrop = false;
        [Tooltip("库存改变时是否自动重载")]
        public bool reloadOnChanged = true;

        [Header("输入行为")]
        [Tooltip("主要按键(左键)拾取操作")]
        public PickAction primaryPickAction = PickAction.PickAll;
        [Tooltip("主要按键(左键)放下操作")]
        public DropAction primaryDropAction = DropAction.DropAll;
        [Tooltip("次要按键(右键)拾取操作")]
        public PickAction secondaryPickAction = PickAction.PickHalf;
        [Tooltip("次要按键(右键)放下操作")]
        public DropAction secondaryDropAction = DropAction.DropOne;

        [Header("拾取放下行为")]
        [Tooltip("拿起物品时的行为")]
        public PickBehaviour pickBehaviour = PickBehaviour.Pick;
        [Tooltip("放入自身库存时的行为")]
        public DropIntoSelfInventory dropIntoSelfInventory = DropIntoSelfInventory.DropCombineSwap;
        [Tooltip("放入其他库存时的行为")]
        public DropIntoOtherInventory dropIntoOtherInventory = DropIntoOtherInventory.ByReceiver;
        [Tooltip("接收其他库存物品时的行为")]
        public ReceiveFromOtherInventory receiveFromOtherInventory = ReceiveFromOtherInventory.DropCombineSwap;
        [Tooltip("放入背景界面时的行为")]
        public DropOnBackground dropOnBackground = DropOnBackground.Destroy;

        /// <summary>
        /// 点击物品回调Action&lt;物品索引&gt;
        /// </summary>
        public System.Action<int> onClickItem;

        /// <summary>
        /// 选中回调Action&lt;物品索引&gt;
        /// </summary>
        public System.Action<int> onSelected;

        /// <summary>
        /// 创建图标回调
        /// </summary>
        public System.Action<GameObject> onAfterCreateItem;

        /// <summary>
        /// 更新图标回调
        /// </summary>
        public System.Action<IItemUI, int> onAfterUpdateItem;

        /// <summary>
        /// 存有物品数据的库存
        /// </summary>
        public Inventory Inventory { get; private set; }

        private PointerHandler pointerHandler; // 指针操作处理器
        private bool gridViewInitialized;
        private bool needReload = false;
        private int _selectedIndex = -1;

        private void Awake() {

        }

        private void OnDestroy() {
            if (gridView != null) {
                gridView.onCreateItem = null;
                gridView.onUpdateItem = null;
                gridView = null;
            }
            if (Inventory != null) {
                Inventory.onChanged -= OnInventoryChanged;
                Inventory = null;
            }
            pointerHandler = null;
            onClickItem = null;
            onSelected = null;
        }

        /// <summary>
        /// 使用外置Inventory初始化
        /// </summary>
        /// <param name="inventory">存有物品数据的库存，基于库存实现各种回调</param>
        /// <param name="pointerHandler">指针操作处理器</param>
        /// <param name="onClickItem">点击物品图标回调Action&lt;索引&gt;</param>
        /// <param name="onSelected">选中回调Action&lt;物品索引&gt;</param>
        public void Init(Inventory inventory, PointerHandler pointerHandler = null, System.Action<int> onClickItem = null, System.Action<int> onSelected = null) {
            Inventory = inventory;
            this.pointerHandler = pointerHandler;
            this.onClickItem = onClickItem;
            this.onSelected = onSelected;

            inventory.onChanged += OnInventoryChanged;
            needReload = inventory != null;
        }

        /// <summary>
        /// 使用数据初始化，会自动创建Inventory
        /// </summary>
        /// <param name="pointerHandler">指针操作处理器</param>
        /// <param name="onClickItem">点击物品图标回调Action&lt;索引&gt;</param>
        /// <param name="onSelected">选中回调Action&lt;物品索引&gt;</param>
        public void Init(Item[] items = null, string onChangedKey = null, PointerHandler pointerHandler = null, System.Action<int> onClickItem = null, System.Action<int> onSelected = null) {
            InventorySetting setting = new InventorySetting() {
                onChangedKey = onChangedKey,
                setEmptyOnZero = setEmptyOnZero,
                pickBehaviour = pickBehaviour,
                dropIntoSelfInventory = dropIntoSelfInventory,
                dropIntoOtherInventory = dropIntoOtherInventory,
                receiveFromOtherInventory = receiveFromOtherInventory,
                dropOnBackground = dropOnBackground
            };
            Inventory = new Inventory(setting, items);

            Init(Inventory, pointerHandler, onClickItem, onSelected);
        }

        private void LateUpdate() {
            // 一帧内多次调用刷新时，保证仅刷新一次
            if (needReload) {
                needReload = false;
                Reload(false);
            }
        }

        /// <summary>
        /// 库存改变事件回调
        /// </summary>
        private void OnInventoryChanged(int[] indexArray) {
            if (reloadOnChanged) {
                needReload = true; // 刷新界面
            }
        }

        /// <summary>
        /// 根据inventory数据刷新界面
        /// </summary>
        /// <param name="reset">是否重置滚动条位置</param>
        public void Reload(bool reset = false) {
            if (!gridViewInitialized && gridView != null) {
                gridView.onCreateItem = OnCreateItem;
                gridView.onUpdateItem = OnUpdateItem;
                gridViewInitialized = true;
            }
            if (viewType == ViewType.GridView && gridView != null) {
                gridView.Reload(Inventory.Count, reset);
            }
            else if (viewType == ViewType.Container && container != null) {
                ReloadContainer(Inventory.Count);
            }
            else {
                Debug.LogError("Invalid setting");
            }
        }

        /// <summary>
        /// 设置/获取当前选中的索引，没选中返回-1
        /// </summary>
        public int SelectedIndex {
            get {
                return _selectedIndex;
            }
            set {
                if(toggleSelected && _selectedIndex == value) {
                    _selectedIndex = -1;
                }
                else {
                    _selectedIndex = value;
                }
                needReload = true;
                onSelected?.Invoke(_selectedIndex);
            }
        }

        public GameObject GetItem(int index) {
            if (viewType == ViewType.GridView && gridView != null) {
                return gridView.GetItem(index);
            }
            else if (viewType == ViewType.Container && container != null) {
                if (index >= 0 && index < container.childCount) {
                    return container.GetChild(index).gameObject;
                }
                else {
                    Debug.LogError("Invalid index " + index);
                    return null;
                }
            }
            else {
                return null;
            }
        }

        private GameObject OnCreateItem() {
            ItemIconSetting setting = new ItemIconSetting { showBg = showBg, showIndex = showIndex, indexOffset = indexOffset, showNum = showNum, showMaxNum = showMaxNum, showSelected = showSelected, numFormat = numFormat };

            GameObject obj = customItemPrefab == null ? Instantiate(DefaultItemPrefab) : Object.Instantiate(customItemPrefab.gameObject);
            IItemUI itemUI = obj.GetComponent<IItemUI>();
            itemUI.Init(setting, pointerHandler, OnPointerClick);

            onAfterCreateItem?.Invoke(obj);

            return obj;
        }

        private void OnUpdateItem(GameObject obj, int index) {
            IItemUI itemUI = obj.GetComponent<IItemUI>();
            itemUI.Set(Inventory.Items[index], index, index == SelectedIndex);

            onAfterUpdateItem?.Invoke(itemUI, index);
        }

        private void ReloadContainer(int dataCount) {
            int destroyCount = container.childCount - dataCount;
            for (int i = 0; i < destroyCount; i++) {
                Destroy(container.GetChild(0).gameObject);
            }

            int addCount = dataCount - container.childCount;
            for (int i = 0; i < addCount; i++) {
                GameObject obj = OnCreateItem();
                obj.transform.SetParent(container, false);
            }

            for (int i = 0; i < dataCount; i++) {
                GameObject obj = container.GetChild(i).gameObject;
                OnUpdateItem(obj, i);
            }
        }

        /// <summary>
        /// 指针点击事件
        /// </summary>
        private void OnPointerClick(IItemUI itemUI, PointerEventData eventData) {
            if (enablePickAndDrop) {
                //bool shift = InputManager.Instance.IsHolding("Shift"); // 当前是否按下shift
                // TODO 

                if (eventData.button == PointerEventData.InputButton.Left) {
                    // 主要按键点击
                    InventoryUtil.OnClickItem(Inventory, itemUI.Index, itemUI, primaryPickAction, primaryDropAction);
                }
                else if (eventData.button == PointerEventData.InputButton.Right) {
                    // 次要按键点击
                    InventoryUtil.OnClickItem(Inventory, itemUI.Index, itemUI, secondaryPickAction, secondaryDropAction);
                }
            }
            else {
                SelectedIndex = itemUI.Index;
                onClickItem?.Invoke(itemUI.Index);
            }
        }

    }


#if UNITY_EDITOR
    [CustomEditor(typeof(ItemView))]
    [CanEditMultipleObjects]
    public class ItemViewEditor : Editor {

        private SerializedProperty showBg;
        private SerializedProperty showIndex;
        private SerializedProperty indexOffset;
        private SerializedProperty showNum;
        private SerializedProperty showMaxNum;
        private SerializedProperty showSelected;
        private SerializedProperty toggleSelected;
        private SerializedProperty numFormat;

        private SerializedProperty setEmptyOnZero;
        private SerializedProperty enablePickAndDrop;
        private SerializedProperty reloadOnChanged;

        private SerializedProperty primaryPickAction;
        private SerializedProperty primaryDropAction;
        private SerializedProperty secondaryPickAction;
        private SerializedProperty secondaryDropAction;

        private SerializedProperty pickBehaviour;
        private SerializedProperty dropIntoSelfInventory;
        private SerializedProperty dropIntoOtherInventory;
        private SerializedProperty receiveFromOtherInventory;
        private SerializedProperty dropOnBackground;

        private SerializedProperty viewType;
        private SerializedProperty gridView;
        private SerializedProperty container;

        private void OnEnable() {
            viewType = serializedObject.FindProperty("viewType");
            gridView = serializedObject.FindProperty("gridView");
            container = serializedObject.FindProperty("container");

            showBg = serializedObject.FindProperty("showBg");
            showIndex = serializedObject.FindProperty("showIndex");
            indexOffset = serializedObject.FindProperty("indexOffset");
            showNum = serializedObject.FindProperty("showNum");
            showMaxNum = serializedObject.FindProperty("showMaxNum");
            showSelected = serializedObject.FindProperty("showSelected");
            toggleSelected = serializedObject.FindProperty("toggleSelected");
            numFormat = serializedObject.FindProperty("numFormat");

            setEmptyOnZero = serializedObject.FindProperty("setEmptyOnZero");
            enablePickAndDrop = serializedObject.FindProperty("enablePickAndDrop");
            reloadOnChanged = serializedObject.FindProperty("reloadOnChanged");

            primaryPickAction = serializedObject.FindProperty("primaryPickAction");
            primaryDropAction = serializedObject.FindProperty("primaryDropAction");
            secondaryPickAction = serializedObject.FindProperty("secondaryPickAction");
            secondaryDropAction = serializedObject.FindProperty("secondaryDropAction");

            pickBehaviour = serializedObject.FindProperty("pickBehaviour");
            dropIntoSelfInventory = serializedObject.FindProperty("dropIntoSelfInventory");
            dropIntoOtherInventory = serializedObject.FindProperty("dropIntoOtherInventory");
            receiveFromOtherInventory = serializedObject.FindProperty("receiveFromOtherInventory");
            dropOnBackground = serializedObject.FindProperty("dropOnBackground");
        }

        public override void OnInspectorGUI() {
            serializedObject.Update();

            EditorGUILayout.PropertyField(viewType);
            if (viewType.enumValueIndex == (int)ViewType.GridView) {
                EditorGUILayout.PropertyField(gridView);
            }
            else if (viewType.enumValueIndex == (int)ViewType.Container) {
                EditorGUILayout.PropertyField(container);
            }

            EditorGUILayout.PropertyField(showBg);
            EditorGUILayout.PropertyField(showIndex);
            if (showIndex.boolValue) {
                EditorGUILayout.PropertyField(indexOffset);
            }
            EditorGUILayout.PropertyField(showNum);
            EditorGUILayout.PropertyField(showMaxNum);
            EditorGUILayout.PropertyField(showSelected);
            EditorGUILayout.PropertyField(toggleSelected);
            EditorGUILayout.PropertyField(numFormat);

            EditorGUILayout.PropertyField(setEmptyOnZero);
            EditorGUILayout.PropertyField(enablePickAndDrop);
            EditorGUILayout.PropertyField(reloadOnChanged);

            EditorGUILayout.PropertyField(primaryPickAction);
            EditorGUILayout.PropertyField(primaryDropAction);
            EditorGUILayout.PropertyField(secondaryPickAction);
            EditorGUILayout.PropertyField(secondaryDropAction);

            EditorGUILayout.PropertyField(pickBehaviour);
            EditorGUILayout.PropertyField(dropIntoSelfInventory);
            EditorGUILayout.PropertyField(dropIntoOtherInventory);
            EditorGUILayout.PropertyField(receiveFromOtherInventory);
            EditorGUILayout.PropertyField(dropOnBackground);
            
            serializedObject.ApplyModifiedProperties();
        }

    }
#endif

}
